package com.kl.controller;

import com.kl.model.BrandEntity;
import com.kl.model.R;
import com.kl.valid.AddGroup;
import com.kl.valid.UpdateGroup;
import com.kl.service.BrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;

@RestController
public class BrandController {

    @Autowired
    BrandService brandService;

    // 不仅要再校验的类上表面具体的校验规则，还要配合@Valid才能真正的开启校验功能
    // 校验错误会被封装到BindingResult 类中，如果没有写BindingResult 参数，会自动抛出异常
    @PostMapping("/save1")
    public R save1(@Valid @RequestBody BrandEntity brand, BindingResult result) {
        if (result.hasErrors()) {
            Map<String, String> map = new HashMap<>();
            result.getFieldErrors().forEach(item -> {
                // 校验未通过的属性和对于的错误信息
                String field = item.getField();
                String message = item.getDefaultMessage();
                map.put(field, message);
            });
            // R是自定义类用来封装返回值
            return R.error(400, "提交数据不合法").put("data", map);
        } else {
            brandService.save(brand);
            return R.ok();
        }
    }

    /**
     * 对于上面的例子，如果有很多接口，那么我们就需要在每一个接口上都手动的通过
     * BindingResult去获取错误并封装错误信息，这是非常麻烦的，基于此问题可以
     * 使用全局异常捕获
     */
    @PostMapping("/save2")
    public R save2(@Valid @RequestBody BrandEntity brand) {
        // 不用再关系错误的逻辑，出错后会自动抛出，交给全局异常控制器解决
        brandService.save(brand);
        return R.ok();
    }

    /**
     * 背景说明：
     * 对于检验来说，不同的业务需要为我们提供不同的校验方法
     * 比如将对象插入数据库，由于主键是自增的，那么对象id必须为空
     * 但如果要更新对象，那么对象id一定不能为空
     * 对于一个对象，我们需要不同的校验规则，那么我们就可以使用分组校验
     * 分组校验的使用规则：
     * 1、定义不同的接口，用接口来区别不同的分组
     * 2、在实体类校验注解中通过group属性来划分不同的分组以此来匹配不同的校验规则
     * 3、需要将@Valid注解换成@Validated注解,且必须指定要校验的组
     * 缺点：如果要使用分组校验，那么就要为每一个需要校验的实体属性都指定分组，不指定分组默认不校验
     */
    @PostMapping("/save3")
    public R save3(@Validated({AddGroup.class}) @RequestBody BrandEntity brand) {
        // 不用再关系错误的逻辑，出错后会自动抛出，交给全局异常控制器解决
        brandService.save(brand);
        return R.ok();
    }

    @PostMapping("/update")
    public R update(@Validated({UpdateGroup.class}) @RequestBody BrandEntity brand) {
        // 不用再关系错误的逻辑，出错后会自动抛出，交给全局异常控制器解决
        brandService.update(brand);
        return R.ok();
    }
}
